package cc.shacocloud.mirage.utils;


import cc.shacocloud.mirage.utils.charSequence.StrUtil;
import cc.shacocloud.mirage.utils.map.ConcurrentReferenceHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Ant 风格的路径匹配器
 *
 * <p>匹配URL的规则如下：<br>
 * <ul>
 * <li>{@code ?} 匹配单个字符</li>
 * <li>{@code *} 匹配0个或多个字符</li>
 * <li>{@code **} 0个或多个路径中的<em>目录节点</em></li>
 * <li>{@code {mirage:[a-z]+}} 匹配以"mirage"命名的正则 {@code [a-z]+}</li>
 * </ul>
 *
 * <p>例子: </p>
 * <ul>
 * <li>{@code com/t?st.jsp} &mdash; 匹配 {@code com/test.jsp} 或 {@code com/tast.jsp} 或 {@code com/txst.jsp}</li>
 * <li>{@code com/*.jsp} &mdash; 匹配{@code com}目录下全部 {@code .jsp}文件</li>
 * <li>{@code com/&#42;&#42;/test.jsp} &mdash; 匹配{@code com}目录下全部 {@code test.jsp}文件</li>
 * <li>{@code cn/mirage/&#42;&#42;/*.jsp} &mdash; 匹配{@code cn/mirage}路径下全部{@code .jsp} 文件</li>
 * <li>{@code org/&#42;&#42;/servlet/bla.jsp} &mdash; 匹配{@code cn/mirage/servlet/bla.jsp} 或{@code cn/mirage/testing/servlet/bla.jsp} 或 {@code org/servlet/bla.jsp}</li>
 * <li>{@code com/{filename:\\w+}.jsp} 匹配 {@code com/test.jsp} 并将 {@code test} 关联到 {@code filename} 变量</li>
 * </ul>
 *
 * <p><strong>注意:</strong> 表达式和路径必须都为绝对路径或都为相对路径。
 */
public class AntPathMatcher implements PathMatcher {
    
    /**
     * 默认的路径分割符: "/".
     */
    public static final String DEFAULT_PATH_SEPARATOR = "/";
    
    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{[^/]+?}");
    
    private static final char[] WILDCARD_CHARS = {'*', '?', '{'};
    private final Map<String, String[]> tokenizedPatternCache = new ConcurrentReferenceHashMap<>(256);
    private final Map<String, AntPathStringMatcher> stringMatcherCache = new ConcurrentReferenceHashMap<>(256);
    private String pathSeparator;
    private PathSeparatorPatternCache pathSeparatorPatternCache;
    // 是否区分大小写
    private boolean caseSensitive = true;
    // 是否去除切分字符串后每个元素两边的空格
    private boolean trimTokens = false;
    // 是否开启缓存
    private Boolean cachePatterns = true;
    
    /**
     * 使用 {@link #DEFAULT_PATH_SEPARATOR} 作为分隔符构造
     */
    public AntPathMatcher() {
        this(DEFAULT_PATH_SEPARATOR);
    }
    
    /**
     * 使用自定义的分隔符构造
     *
     * @param pathSeparator 要使用的路径分隔符，不能是{@code null}
     */
    public AntPathMatcher(String pathSeparator) {
        if (null == pathSeparator) {
            pathSeparator = DEFAULT_PATH_SEPARATOR;
        }
        setPathSeparator(pathSeparator);
    }
    
    
    /**
     * 设置路径分隔符
     *
     * @param pathSeparator 分隔符，{@code null}表示使用默认分隔符{@link #DEFAULT_PATH_SEPARATOR}
     * @return this
     */
    public AntPathMatcher setPathSeparator(String pathSeparator) {
        if (null == pathSeparator) {
            pathSeparator = DEFAULT_PATH_SEPARATOR;
        }
        this.pathSeparator = pathSeparator;
        this.pathSeparatorPatternCache = new PathSeparatorPatternCache(this.pathSeparator);
        return this;
    }
    
    /**
     * 设置是否大小写敏感，默认为{@code true}
     *
     * @param caseSensitive 是否大小写敏感
     * @return this
     */
    public AntPathMatcher setCaseSensitive(boolean caseSensitive) {
        this.caseSensitive = caseSensitive;
        return this;
    }
    
    /**
     * 设置是否去除路径节点两边的空白符，默认为{@code false}
     *
     * @param trimTokens 是否去除路径节点两边的空白符
     * @return this
     */
    public AntPathMatcher setTrimTokens(boolean trimTokens) {
        this.trimTokens = trimTokens;
        return this;
    }
    
    /**
     * 指定是否缓存传递到此匹配器的{@link #match}方法的模式的已解析模式元数据。
     * {@code true}激活缓存模式;
     * {@code false}将关闭缓存模式。
     *
     * @param cachePatterns 是否缓存表达式
     * @return this
     * @see #getStringMatcher(String)
     */
    public AntPathMatcher setCachePatterns(boolean cachePatterns) {
        this.cachePatterns = cachePatterns;
        return this;
    }
    
    /**
     * 判断给定路径是否是表达式
     *
     * @param path 路径
     * @return 是否为表达式
     */
    @Override
    public boolean isPattern(@Nullable String path) {
        if (path == null) {
            return false;
        }
        boolean uriVar = false;
        for (int i = 0; i < path.length(); i++) {
            char c = path.charAt(i);
            if (c == '*' || c == '?') {
                return true;
            }
            if (c == '{') {
                uriVar = true;
                continue;
            }
            if (c == '}' && uriVar) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 给定路径是否匹配表达式
     *
     * @param pattern 表达式
     * @param path    路径
     * @return 是否匹配
     */
    @Override
    public boolean match(String pattern, String path) {
        return doMatch(pattern, path, true, null);
    }
    
    /**
     * 前置部分匹配
     *
     * @param pattern 表达式
     * @param path    路径
     * @return 是否匹配
     */
    @Override
    public boolean matchStart(String pattern, String path) {
        return doMatch(pattern, path, false, null);
    }
    
    /**
     * 执行匹配，判断给定的{@code path}是否匹配{@code pattern}
     *
     * @param pattern              表达式
     * @param path                 路径
     * @param fullMatch            是否全匹配。{@code true} 表示全路径匹配，{@code false}表示只匹配开始
     * @param uriTemplateVariables 变量映射
     * @return {@code true} 表示提供的 {@code path} 匹配, {@code false} 表示不匹配
     */
    protected boolean doMatch(String pattern, String path, boolean fullMatch, Map<String, String> uriTemplateVariables) {
        if (path == null || path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
            return false;
        }
        
        final String[] pattDirs = tokenizePattern(pattern);
        if (fullMatch && this.caseSensitive && !isPotentialMatch(path, pattDirs)) {
            return false;
        }
        
        final String[] pathDirs = tokenizePath(path);
        int pattIdxStart = 0;
        int pattIdxEnd = pattDirs.length - 1;
        int pathIdxStart = 0;
        int pathIdxEnd = pathDirs.length - 1;
        
        // 匹配第一个之前的所有元素
        while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
            String pattDir = pattDirs[pattIdxStart];
            if ("**".equals(pattDir)) {
                break;
            }
            if (notMatchStrings(pattDir, pathDirs[pathIdxStart], uriTemplateVariables)) {
                return false;
            }
            pattIdxStart++;
            pathIdxStart++;
        }
        
        if (pathIdxStart > pathIdxEnd) {
            // 路径已耗尽，仅当模式的其余部分为或时匹配
            if (pattIdxStart > pattIdxEnd) {
                return (pattern.endsWith(this.pathSeparator) == path.endsWith(this.pathSeparator));
            }
            if (!fullMatch) {
                return true;
            }
            if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && path.endsWith(this.pathSeparator)) {
                return true;
            }
            for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
                if (!pattDirs[i].equals("**")) {
                    return false;
                }
            }
            return true;
        } else if (pattIdxStart > pattIdxEnd) {
            // 字符串未耗尽，但模式已耗尽。失败。
            return false;
        } else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) {
            // 由于模式中的 “**” 部分，路径开始肯定匹配。
            return true;
        }
        
        // 直到最后 **
        while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
            String pattDir = pattDirs[pattIdxEnd];
            if (pattDir.equals("**")) {
                break;
            }
            if (notMatchStrings(pattDir, pathDirs[pathIdxEnd], uriTemplateVariables)) {
                return false;
            }
            pattIdxEnd--;
            pathIdxEnd--;
        }
        if (pathIdxStart > pathIdxEnd) {
            // 字符串已耗尽
            for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
                if (!pattDirs[i].equals("**")) {
                    return false;
                }
            }
            return true;
        }
        
        while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
            int patIdxTmp = -1;
            for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
                if (pattDirs[i].equals("**")) {
                    patIdxTmp = i;
                    break;
                }
            }
            if (patIdxTmp == pattIdxStart + 1) {
                // '**/**' 情境，跳过一个
                pattIdxStart++;
                continue;
            }
            // 在strIdxStart和strIdxEnd之间的str中找到padIdxStart和padIdxTmp之间的模式
            int patLength = (patIdxTmp - pattIdxStart - 1);
            int strLength = (pathIdxEnd - pathIdxStart + 1);
            int foundIdx = -1;
            
            strLoop:
            for (int i = 0; i <= strLength - patLength; i++) {
                for (int j = 0; j < patLength; j++) {
                    String subPat = pattDirs[pattIdxStart + j + 1];
                    String subStr = pathDirs[pathIdxStart + i + j];
                    if (notMatchStrings(subPat, subStr, uriTemplateVariables)) {
                        continue strLoop;
                    }
                }
                foundIdx = pathIdxStart + i;
                break;
            }
            
            if (foundIdx == -1) {
                return false;
            }
            
            pattIdxStart = patIdxTmp;
            pathIdxStart = foundIdx + patLength;
        }
        
        for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
            if (!pattDirs[i].equals("**")) {
                return false;
            }
        }
        
        return true;
    }
    
    private boolean isPotentialMatch(String path, String[] pattDirs) {
        if (!this.trimTokens) {
            int pos = 0;
            for (String pattDir : pattDirs) {
                int skipped = skipSeparator(path, pos, this.pathSeparator);
                pos += skipped;
                skipped = skipSegment(path, pos, pattDir);
                if (skipped < pattDir.length()) {
                    return (skipped > 0 || (pattDir.length() > 0 && isWildcardChar(pattDir.charAt(0))));
                }
                pos += skipped;
            }
        }
        return true;
    }
    
    private int skipSegment(String path, int pos, @NotNull String prefix) {
        int skipped = 0;
        for (int i = 0; i < prefix.length(); i++) {
            char c = prefix.charAt(i);
            if (isWildcardChar(c)) {
                return skipped;
            }
            int currPos = pos + skipped;
            if (currPos >= path.length()) {
                return 0;
            }
            if (c == path.charAt(currPos)) {
                skipped++;
            }
        }
        return skipped;
    }
    
    private int skipSeparator(@NotNull String path, int pos, String separator) {
        int skipped = 0;
        while (path.startsWith(separator, pos + skipped)) {
            skipped += separator.length();
        }
        return skipped;
    }
    
    private boolean isWildcardChar(char c) {
        for (char candidate : WILDCARD_CHARS) {
            if (c == candidate) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 根据这个匹配器的设置，将给定的路径模式标记为各个部分
     * <p>
     * 基于{@link #setCachePatterns}执行缓存，将实际的标记化算法委托给{@link #tokenizePath(String)}
     *
     * @param pattern 要标记的模式
     * @return 标记化的模式部分
     */
    protected String[] tokenizePattern(String pattern) {
        String[] tokenized = null;
        Boolean cachePatterns = this.cachePatterns;
        if (cachePatterns == null || cachePatterns) {
            tokenized = this.tokenizedPatternCache.get(pattern);
        }
        
        if (tokenized == null) {
            tokenized = tokenizePath(pattern);
            if (cachePatterns == null || cachePatterns) {
                this.tokenizedPatternCache.put(pattern, tokenized);
            }
        }
        return tokenized;
    }
    
    /**
     * 根据这个匹配器的设置，将给定的路径标记为多个部分
     *
     * @param path 标记化的路径
     * @return 标记化的路径部分
     */
    protected String[] tokenizePath(String path) {
        return StrUtil.splitToArray(path, this.pathSeparator, 0, this.trimTokens, true);
    }
    
    /**
     * 测试字符串是否与模式匹配
     *
     * @param pattern 要匹配的模式(never {@code null})
     * @param str     必须与模式匹配的字符串(never {@code null})
     * @return 如果字符串与模式匹配{@code true}，否则为{@code false}
     */
    private boolean notMatchStrings(String pattern, String str, Map<String, String> uriTemplateVariables) {
        return !getStringMatcher(pattern).matchStrings(str, uriTemplateVariables);
    }
    
    /**
     * 为给定的模式构建或检索{@link AntPathStringMatcher}。
     * <p>
     * 默认实现检查这个 AntPathStringMatcher 的内部缓存(参见{@link #setCachePatterns})，如果没有找到缓存副本，就创建一个新的AntPathStringMatcher实例。
     *
     * @param pattern 要匹配的模式
     * @return 一个对应的 AntPathStringMatcher
     * @see #setCachePatterns
     */
    @NotNull
    protected AntPathStringMatcher getStringMatcher(@NotNull String pattern) {
        AntPathStringMatcher matcher = null;
        Boolean cachePatterns = this.cachePatterns;
        if (cachePatterns == null || cachePatterns) {
            matcher = this.stringMatcherCache.get(pattern);
        }
        
        if (matcher == null) {
            matcher = new AntPathStringMatcher(pattern, this.caseSensitive);
            
            if (cachePatterns == null || cachePatterns) {
                this.stringMatcherCache.put(pattern, matcher);
            }
        }
        return matcher;
    }
    
    /**
     * 给定一个模式和一个完整路径，确定模式映射部分。
     * <p>
     * 例如:
     * <ul>
     * <li>'{@code /docs/cvs/commit.html}' and '{@code /docs/cvs/commit.html} &rarr; ''</li>
     * <li>'{@code /docs/*}' and '{@code /docs/cvs/commit} &rarr; '{@code cvs/commit}'</li>
     * <li>'{@code /docs/cvs/*.html}' and '{@code /docs/cvs/commit.html} &rarr; '{@code commit.html}'</li>
     * <li>'{@code /docs/**}' and '{@code /docs/cvs/commit} &rarr; '{@code cvs/commit}'</li>
     * <li>'{@code /docs/**\/*.html}' and '{@code /docs/cvs/commit.html} &rarr; '{@code cvs/commit.html}'</li>
     * <li>'{@code /*.html}' and '{@code /docs/cvs/commit.html} &rarr; '{@code docs/cvs/commit.html}'</li>
     * <li>'{@code *.html}' and '{@code /docs/cvs/commit.html} &rarr; '{@code /docs/cvs/commit.html}'</li>
     * <li>'{@code *}' and '{@code /docs/cvs/commit.html} &rarr; '{@code /docs/cvs/commit.html}'</li>
     * </ul>
     * <p>
     *
     * @param pattern 表达式
     * @param path    路径
     * @return 表达式匹配到的部分
     */
    @Override
    public String extractPathWithinPattern(String pattern, String path) {
        String[] patternParts = tokenizePath(pattern);
        String[] pathParts = tokenizePath(path);
        StringBuilder builder = new StringBuilder();
        boolean pathStarted = false;
        
        for (int segment = 0; segment < patternParts.length; segment++) {
            String patternPart = patternParts[segment];
            if (patternPart.indexOf('*') > -1 || patternPart.indexOf('?') > -1) {
                for (; segment < pathParts.length; segment++) {
                    if (pathStarted || (segment == 0 && !pattern.startsWith(this.pathSeparator))) {
                        builder.append(this.pathSeparator);
                    }
                    builder.append(pathParts[segment]);
                    pathStarted = true;
                }
            }
        }
        
        return builder.toString();
    }
    
    @Override
    public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
        Map<String, String> variables = new LinkedHashMap<>();
        boolean result = doMatch(pattern, path, true, variables);
        if (!result) {
            throw new IllegalStateException("Pattern \"" + pattern + "\" is not a match for \"" + path + "\"");
        }
        return variables;
    }
    
    /**
     * 这个实现只是简单地连接两个模式，除非第一个模式包含文件扩展名匹配(例如，{@code .html})。
     * 在这种情况下，第二个模式将合并到第一个模式中。否则，将抛出{@code IllegalArgumentException}。
     * <p>
     * 例子
     * <table border="1" summary="">
     * <tr><th>Pattern 1</th><th>Pattern 2</th><th>Result</th></tr>
     * <tr><td>{@code null}</td><td>{@code null}</td><td>&nbsp;</td></tr>
     * <tr><td>/hotels</td><td>{@code null}</td><td>/hotels</td></tr>
     * <tr><td>{@code null}</td><td>/hotels</td><td>/hotels</td></tr>
     * <tr><td>/hotels</td><td>/bookings</td><td>/hotels/bookings</td></tr>
     * <tr><td>/hotels</td><td>bookings</td><td>/hotels/bookings</td></tr>
     * <tr><td>/hotels/*</td><td>/bookings</td><td>/hotels/bookings</td></tr>
     * <tr><td>/hotels/&#42;&#42;</td><td>/bookings</td><td>/hotels/&#42;&#42;/bookings</td></tr>
     * <tr><td>/hotels</td><td>{hotel}</td><td>/hotels/{hotel}</td></tr>
     * <tr><td>/hotels/*</td><td>{hotel}</td><td>/hotels/{hotel}</td></tr>
     * <tr><td>/hotels/&#42;&#42;</td><td>{hotel}</td><td>/hotels/&#42;&#42;/{hotel}</td></tr>
     * <tr><td>/*.html</td><td>/hotels.html</td><td>/hotels.html</td></tr>
     * <tr><td>/*.html</td><td>/hotels</td><td>/hotels.html</td></tr>
     * <tr><td>/*.html</td><td>/*.txt</td><td>{@code IllegalArgumentException}</td></tr>
     * </table>
     */
    @Override
    public String combine(String pattern1, String pattern2) {
        if (StrUtil.isEmpty(pattern1) && StrUtil.isEmpty(pattern2)) {
            return StrUtil.EMPTY;
        }
        if (StrUtil.isEmpty(pattern1)) {
            return pattern2;
        }
        if (StrUtil.isEmpty(pattern2)) {
            return pattern1;
        }
        
        boolean pattern1ContainsUriVar = (pattern1.indexOf('{') != -1);
        if (!pattern1.equals(pattern2) && !pattern1ContainsUriVar && match(pattern1, pattern2)) {
            // /* + /hotel -> /hotel ; "/*.*" + "/*.html" -> /*.html
            // However /user + /user -> /usr/user ; /{foo} + /bar -> /{foo}/bar
            return pattern2;
        }
        
        // /hotels/* + /booking -> /hotels/booking
        // /hotels/* + booking -> /hotels/booking
        if (pattern1.endsWith(this.pathSeparatorPatternCache.getEndsOnWildCard())) {
            return concat(pattern1.substring(0, pattern1.length() - 2), pattern2);
        }
        
        // /hotels/** + /booking -> /hotels/**/booking
        // /hotels/** + booking -> /hotels/**/booking
        if (pattern1.endsWith(this.pathSeparatorPatternCache.getEndsOnDoubleWildCard())) {
            return concat(pattern1, pattern2);
        }
        
        int starDotPos1 = pattern1.indexOf("*.");
        if (pattern1ContainsUriVar || starDotPos1 == -1 || this.pathSeparator.equals(".")) {
            // simply concatenate the two patterns
            return concat(pattern1, pattern2);
        }
        
        String ext1 = pattern1.substring(starDotPos1 + 1);
        int dotPos2 = pattern2.indexOf('.');
        String file2 = (dotPos2 == -1 ? pattern2 : pattern2.substring(0, dotPos2));
        String ext2 = (dotPos2 == -1 ? "" : pattern2.substring(dotPos2));
        boolean ext1All = (ext1.equals(".*") || ext1.isEmpty());
        boolean ext2All = (ext2.equals(".*") || ext2.isEmpty());
        if (!ext1All && !ext2All) {
            throw new IllegalArgumentException("不能组合模式: " + pattern1 + " vs " + pattern2);
        }
        String ext = (ext1All ? ext2 : ext1);
        return file2 + ext;
    }
    
    private @NotNull String concat(String path1, String path2) {
        boolean path1EndsWithSeparator = path1.endsWith(this.pathSeparator);
        boolean path2StartsWithSeparator = path2.startsWith(this.pathSeparator);
        
        if (path1EndsWithSeparator && path2StartsWithSeparator) {
            return path1 + path2.substring(1);
        } else if (path1EndsWithSeparator || path2StartsWithSeparator) {
            return path1 + path2;
        } else {
            return path1 + this.pathSeparator + path2;
        }
    }
    
    /**
     * 给定一个完整的路径，返回一个{@link Comparator}，适合按显式顺序对模式进行排序。
     * <p>
     * 这个{@code Comparator}将 {@linkplain List#sort(Comparator)} 对列表进行排序，
     * 以便更具体的模式(没有URI模板或通配符)出现在泛型模式之前。
     * 因此，给定一个具有以下模式的列表，返回的比较器将对该列表进行排序，以便按照指示的顺序进行排序。
     * <ol>
     * <li>{@code /hotels/new}</li>
     * <li>{@code /hotels/{hotel}} </li>
     * <li>{@code /hotels/*}</li>
     * </ol>
     * <p>
     * 作为参数给出的完整路径用于测试精确匹配。因此，当给定的路径是{@code hotels2}时，模式{@code hotels2}将被排序在{@code hotels1}之前。
     * <p>
     *
     * @param path 用于比较的完整路径
     * @return 一种能够按显式顺序对模式进行排序的比较器
     */
    @Override
    public Comparator<String> getPatternComparator(String path) {
        return new AntPatternComparator(path);
    }
    
    
    /**
     * 通过{@link Pattern}测试字符串是否与模式匹配。
     * <p>
     * 该模式可能包含特殊字符:"意味着零个或多个字符;”?'表示一个且只有一个字符;“{”和“}”表示URI模板模式。
     * 例如<tt>users{user}<tt>。
     */
    protected static class AntPathStringMatcher {
        
        private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{((?:\\{[^/]+?}|[^/{}]|\\\\[{}])+?)}");
        
        private static final String DEFAULT_VARIABLE_PATTERN = "((?s).*)";
        
        private final String rawPattern;
        
        private final boolean caseSensitive;
        
        private final boolean exactMatch;
        
        private final Pattern pattern;
        
        private final List<String> variableNames = new ArrayList<>();
        
        public AntPathStringMatcher(String pattern, boolean caseSensitive) {
            this.rawPattern = pattern;
            this.caseSensitive = caseSensitive;
            StringBuilder patternBuilder = new StringBuilder();
            Matcher matcher = GLOB_PATTERN.matcher(pattern);
            int end = 0;
            while (matcher.find()) {
                patternBuilder.append(quote(pattern, end, matcher.start()));
                String match = matcher.group();
                if ("?".equals(match)) {
                    patternBuilder.append('.');
                } else if ("*".equals(match)) {
                    patternBuilder.append(".*");
                } else if (match.startsWith("{") && match.endsWith("}")) {
                    int colonIdx = match.indexOf(':');
                    if (colonIdx == -1) {
                        patternBuilder.append(DEFAULT_VARIABLE_PATTERN);
                        this.variableNames.add(matcher.group(1));
                    } else {
                        String variablePattern = match.substring(colonIdx + 1, match.length() - 1);
                        patternBuilder.append('(');
                        patternBuilder.append(variablePattern);
                        patternBuilder.append(')');
                        String variableName = match.substring(1, colonIdx);
                        this.variableNames.add(variableName);
                    }
                }
                end = matcher.end();
            }
            // 没有发现glob模式，这是一个精确的字符串匹配
            if (end == 0) {
                this.exactMatch = true;
                this.pattern = null;
            } else {
                this.exactMatch = false;
                patternBuilder.append(quote(pattern, end, pattern.length()));
                this.pattern = (this.caseSensitive ? Pattern.compile(patternBuilder.toString()) :
                        Pattern.compile(patternBuilder.toString(), Pattern.CASE_INSENSITIVE));
            }
        }
        
        private @NotNull String quote(String s, int start, int end) {
            if (start == end) {
                return "";
            }
            return Pattern.quote(s.substring(start, end));
        }
        
        /**
         * 主要入口。
         *
         * @param str                  Str
         * @param uriTemplateVariables uri template vars
         * @return {@code true} if the string matches against the pattern, or {@code false} otherwise.
         */
        public boolean matchStrings(String str, Map<String, String> uriTemplateVariables) {
            if (this.exactMatch) {
                return this.caseSensitive ? this.rawPattern.equals(str) : this.rawPattern.equalsIgnoreCase(str);
            } else if (this.pattern != null) {
                Matcher matcher = this.pattern.matcher(str);
                if (matcher.matches()) {
                    if (uriTemplateVariables != null) {
                        if (this.variableNames.size() != matcher.groupCount()) {
                            throw new IllegalArgumentException("The number of capturing groups in the pattern segment " +
                                    this.pattern + " does not match the number of URI template variables it defines, " +
                                    "which can occur if capturing groups are used in a URI template regex. " +
                                    "Use non-capturing groups instead.");
                        }
                        for (int i = 1; i <= matcher.groupCount(); i++) {
                            String name = this.variableNames.get(i - 1);
                            if (name.startsWith("*")) {
                                throw new IllegalArgumentException("Capturing patterns (" + name + ") are not " +
                                        "supported by the AntPathMatcher. Use the PathPatternParser instead.");
                            }
                            String value = matcher.group(i);
                            uriTemplateVariables.put(name, value);
                        }
                    }
                    return true;
                }
            }
            return false;
        }
        
    }
    
    
    /**
     * 由 {@link #getPatternComparator(String)}返回的默认{@link Comparator}实现。
     */
    protected static class AntPatternComparator implements Comparator<String> {
        
        private final String path;
        
        public AntPatternComparator(String path) {
            this.path = path;
        }
        
        /**
         * 比较两个模式，以确定哪个应该先匹配，也就是说，对于当前路径，哪个是最具体的
         *
         * @param pattern1 表达式1
         * @param pattern2 表达式2
         * @return 负整数、零或正整数作为pattern1比pattern2更特定、同样特定或更不特定。
         */
        @Override
        public int compare(String pattern1, String pattern2) {
            PatternInfo info1 = new PatternInfo(pattern1);
            PatternInfo info2 = new PatternInfo(pattern2);
            
            if (info1.isLeastSpecific() && info2.isLeastSpecific()) {
                return 0;
            } else if (info1.isLeastSpecific()) {
                return 1;
            } else if (info2.isLeastSpecific()) {
                return -1;
            }
            
            boolean pattern1EqualsPath = pattern1.equals(this.path);
            boolean pattern2EqualsPath = pattern2.equals(this.path);
            if (pattern1EqualsPath && pattern2EqualsPath) {
                return 0;
            } else if (pattern1EqualsPath) {
                return -1;
            } else if (pattern2EqualsPath) {
                return 1;
            }
            
            if (info1.isPrefixPattern() && info2.isPrefixPattern()) {
                return info2.getLength() - info1.getLength();
            } else if (info1.isPrefixPattern() && info2.getDoubleWildcards() == 0) {
                return 1;
            } else if (info2.isPrefixPattern() && info1.getDoubleWildcards() == 0) {
                return -1;
            }
            
            if (info1.getTotalCount() != info2.getTotalCount()) {
                return info1.getTotalCount() - info2.getTotalCount();
            }
            
            if (info1.getLength() != info2.getLength()) {
                return info2.getLength() - info1.getLength();
            }
            
            if (info1.getSingleWildcards() < info2.getSingleWildcards()) {
                return -1;
            } else if (info2.getSingleWildcards() < info1.getSingleWildcards()) {
                return 1;
            }
            
            if (info1.getUriVars() < info2.getUriVars()) {
                return -1;
            } else if (info2.getUriVars() < info1.getUriVars()) {
                return 1;
            }
            
            return 0;
        }
        
        
        /**
         * 值类，它包含关于模式的信息，例如“*”、“**”和“{”模式元素的出现次数。
         */
        private static class PatternInfo {
            
            private final String pattern;
            private int uriVars;
            private int singleWildcards;
            private int doubleWildcards;
            private boolean catchAllPattern;
            private boolean prefixPattern;
            private Integer length;
            
            public PatternInfo(String pattern) {
                this.pattern = pattern;
                if (this.pattern != null) {
                    initCounters();
                    this.catchAllPattern = this.pattern.equals("/**");
                    this.prefixPattern = !this.catchAllPattern && this.pattern.endsWith("/**");
                }
                if (this.uriVars == 0) {
                    this.length = (this.pattern != null ? this.pattern.length() : 0);
                }
            }
            
            protected void initCounters() {
                int pos = 0;
                if (this.pattern != null) {
                    while (pos < this.pattern.length()) {
                        if (this.pattern.charAt(pos) == '{') {
                            this.uriVars++;
                            pos++;
                        } else if (this.pattern.charAt(pos) == '*') {
                            if (pos + 1 < this.pattern.length() && this.pattern.charAt(pos + 1) == '*') {
                                this.doubleWildcards++;
                                pos += 2;
                            } else if (pos > 0 && !this.pattern.substring(pos - 1).equals(".*")) {
                                this.singleWildcards++;
                                pos++;
                            } else {
                                pos++;
                            }
                        } else {
                            pos++;
                        }
                    }
                }
            }
            
            public int getUriVars() {
                return this.uriVars;
            }
            
            public int getSingleWildcards() {
                return this.singleWildcards;
            }
            
            public int getDoubleWildcards() {
                return this.doubleWildcards;
            }
            
            public boolean isLeastSpecific() {
                return (this.pattern == null || this.catchAllPattern);
            }
            
            public boolean isPrefixPattern() {
                return this.prefixPattern;
            }
            
            public int getTotalCount() {
                return this.uriVars + this.singleWildcards + (2 * this.doubleWildcards);
            }
            
            /**
             * 返回给定模式的长度，其中模板变量的长度为1。
             *
             * @return 长度
             */
            public int getLength() {
                if (this.length == null) {
                    this.length = (this.pattern != null ?
                            VARIABLE_PATTERN.matcher(this.pattern).replaceAll("#").length() : 0);
                }
                return this.length;
            }
        }
    }
    
    
    /**
     * 依赖于配置的路径分隔符的模式的简单缓存
     */
    private static class PathSeparatorPatternCache {
        
        private final String endsOnWildCard;
        
        private final String endsOnDoubleWildCard;
        
        public PathSeparatorPatternCache(String pathSeparator) {
            this.endsOnWildCard = pathSeparator + "*";
            this.endsOnDoubleWildCard = pathSeparator + "**";
        }
        
        public String getEndsOnWildCard() {
            return this.endsOnWildCard;
        }
        
        public String getEndsOnDoubleWildCard() {
            return this.endsOnDoubleWildCard;
        }
    }
    
}
